﻿/*

   Copyright 2001,2003  The Apache Software Foundation 

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

 
  C# translation and update 
  Copyright (c) Adam Sida, asida@centrum.cz

  All rights reserved.
*/
using System;
//using System.Drawing;
using System.Windows;


namespace Petra.Gis.ImagingServices.Tiff
{

  public class CompressionCCITT : Compression
  {

    private int bitPointer, bytePointer;
    private byte[] data;
    private int w, h;
    private FillOrderType _fillOrder;
    private TiffFaxT6Option _tiffT6Options;
    private TiffFaxT4Option _tiffT4Options;

    // Data structures needed to store changing elements for the previous
    // and the current scanline
    private int changingElemSize = 0;
    private int[] prevChangingElems;
    private int[] currChangingElems;

    // Element at which to start search in getNextChangingElement
    private int lastChangingElement = 0;

    private int compression = 2;

    // Variables set by T4Options
    //private int uncompressedMode = 0;
    private int fillBits = 0;
    private int oneD;

    private bool _decompressAs8bpp = true;


    #region static tables

    static int[] table1 = 
    {
     0x00, // 0 bits are left in first byte - SHOULD NOT HAPPEN
     0x01, // 1 bits are left in first byte
     0x03, // 2 bits are left in first byte
     0x07, // 3 bits are left in first byte
     0x0f, // 4 bits are left in first byte
     0x1f, // 5 bits are left in first byte
     0x3f, // 6 bits are left in first byte
     0x7f, // 7 bits are left in first byte
     0xff  // 8 bits are left in first byte
    };

    static int[] table2 = 
    {
     0x00, // 0
     0x80, // 1
     0xc0, // 2
     0xe0, // 3
     0xf0, // 4
     0xf8, // 5
     0xfc, // 6
     0xfe, // 7
     0xff  // 8
    };


    // Table to be used when _fillOrder = 2, for flipping bytes.
    
    static sbyte[] flipTable = {
    0,  -128,    64,   -64,    32,   -96,    96,   -32, 
   16,  -112,    80,   -48,    48,   -80,   112,   -16, 
    8,  -120,    72,   -56,    40,   -88,   104,   -24, 
   24,  -104,    88,   -40,    56,   -72,   120,    -8, 
    4,  -124,    68,   -60,    36,   -92,   100,   -28, 
   20,  -108,    84,   -44,    52,   -76,   116,   -12, 
   12,  -116,    76,   -52,    44,   -84,   108,   -20, 
   28,  -100,    92,   -36,    60,   -68,   124,   -4, 
    2,  -126,    66,   -62,    34,   -94,    98,   -30, 
   18,  -110,    82,   -46,    50,   -78,   114,   -14, 
   10,  -118,    74,   -54,    42,   -86,   106,   -22, 
   26,  -102,    90,   -38,    58,   -70,   122,    -6, 
    6,  -122,    70,   -58,    38,   -90,   102,   -26, 
   22,  -106,    86,   -42,    54,   -74,   118,   -10, 
   14,  -114,    78,   -50,    46,   -82,   110,   -18, 
   30,   -98,    94,   -34,    62,   -66,   126,    -2, 
    1,  -127,    65,   -63,    33,   -95,    97,   -31, 
   17,  -111,    81,   -47,    49,   -79,   113,   -15, 
    9,  -119,    73,   -55,    41,   -87,   105,   -23, 
   25,  -103,    89,   -39,    57,   -71,   121,    -7, 
    5,  -123,    69,   -59,    37,   -91,   101,   -27, 
   21,  -107,    85,   -43,    53,   -75,   117,   -11, 
   13,  -115,    77,   -51,    45,   -83,   109,   -19, 
   29,   -99,    93,   -35,    61,   -67,   125,    -3, 
    3,  -125,    67,   -61,    35,   -93,    99,   -29, 
   19,  -109,    83,   -45,    51,   -77,   115,   -13, 
   11,  -117,    75,   -53,    43,   -85,   107,   -21, 
   27,  -101,    91,   -37,    59,   -69,   123,    -5, 
    7,  -121,    71,   -57,    39,   -89,   103,   -25, 
   23,  -105,    87,   -41,    55,   -73,   119,    -9, 
  15,  -113,    79,   -49,    47,   -81,   111,   -17, 
  31,   -97,    95,   -33,    63,   -65,   127,    -1, 
    };

    // The main 10 bit white runs lookup table
    static short[] white = {
  // 0 - 7
  6430,   6400,   6400,   6400,   3225,   3225,   3225,   3225, 
  // 8 - 15
  944,    944,    944,    944,    976,    976,    976,    976, 
  // 16 - 23
  1456,   1456,   1456,   1456,   1488,   1488,   1488,   1488, 
  // 24 - 31
  718,    718,    718,    718,    718,    718,    718,    718, 
  // 32 - 39
  750,    750,    750,    750,    750,    750,    750,    750, 
  // 40 - 47
  1520,   1520,   1520,   1520,   1552,   1552,   1552,   1552, 
  // 48 - 55
  428,    428,    428,    428,    428,    428,    428,    428, 
  // 56 - 63
  428,    428,    428,    428,    428,    428,    428,    428, 
  // 64 - 71
  654,    654,    654,    654,    654,    654,    654,    654, 
  // 72 - 79
  1072,   1072,   1072,   1072,   1104,   1104,   1104,   1104, 
  // 80 - 87
  1136,   1136,   1136,   1136,   1168,   1168,   1168,   1168, 
  // 88 - 95
  1200,   1200,   1200,   1200,   1232,   1232,   1232,   1232, 
  // 96 - 103
  622,    622,    622,    622,    622,    622,    622,    622, 
  // 104 - 111
  1008,   1008,   1008,   1008,   1040,   1040,   1040,   1040, 
  // 112 - 119
  44,     44,     44,     44,     44,     44,     44,     44, 
  // 120 - 127
  44,     44,     44,     44,     44,     44,     44,     44, 
  // 128 - 135
  396,    396,    396,    396,    396,    396,    396,    396, 
  // 136 - 143
  396,    396,    396,    396,    396,    396,    396,    396, 
  // 144 - 151
  1712,   1712,   1712,   1712,   1744,   1744,   1744,   1744, 
  // 152 - 159
  846,    846,    846,    846,    846,    846,    846,    846, 
  // 160 - 167
  1264,   1264,   1264,   1264,   1296,   1296,   1296,   1296, 
  // 168 - 175
  1328,   1328,   1328,   1328,   1360,   1360,   1360,   1360, 
  // 176 - 183
  1392,   1392,   1392,   1392,   1424,   1424,   1424,   1424, 
  // 184 - 191
  686,    686,    686,    686,    686,    686,    686,    686, 
  // 192 - 199
  910,    910,    910,    910,    910,    910,    910,    910, 
  // 200 - 207
  1968,   1968,   1968,   1968,   2000,   2000,   2000,   2000, 
  // 208 - 215
  2032,   2032,   2032,   2032,     16,     16,     16,     16, 
  // 216 - 223
  10257,  10257,  10257,  10257,  12305,  12305,  12305,  12305, 
  // 224 - 231
  330,    330,    330,    330,    330,    330,    330,    330, 
  // 232 - 239
  330,    330,    330,    330,    330,    330,    330,    330, 
  // 240 - 247
  330,    330,    330,    330,    330,    330,    330,    330, 
  // 248 - 255
  330,    330,    330,    330,    330,    330,    330,    330, 
  // 256 - 263
  362,    362,    362,    362,    362,    362,    362,    362, 
  // 264 - 271
  362,    362,    362,    362,    362,    362,    362,    362, 
  // 272 - 279
  362,    362,    362,    362,    362,    362,    362,    362, 
  // 280 - 287
  362,    362,    362,    362,    362,    362,    362,    362, 
  // 288 - 295
  878,    878,    878,    878,    878,    878,    878,    878, 
  // 296 - 303
  1904,   1904,   1904,   1904,   1936,   1936,   1936,   1936, 
  // 304 - 311
        -18413, -18413, -16365, -16365, -14317, -14317, -10221, -10221, 
  // 312 - 319
  590,    590,    590,    590,    590,    590,    590,    590, 
  // 320 - 327
  782,    782,    782,    782,    782,    782,    782,    782, 
  // 328 - 335
  1584,   1584,   1584,   1584,   1616,   1616,   1616,   1616, 
  // 336 - 343
  1648,   1648,   1648,   1648,   1680,   1680,   1680,   1680, 
  // 344 - 351
  814,    814,    814,    814,    814,    814,    814,    814, 
  // 352 - 359
  1776,   1776,   1776,   1776,   1808,   1808,   1808,   1808, 
  // 360 - 367
  1840,   1840,   1840,   1840,   1872,   1872,   1872,   1872, 
  // 368 - 375
  6157,   6157,   6157,   6157,   6157,   6157,   6157,   6157, 
  // 376 - 383
  6157,   6157,   6157,   6157,   6157,   6157,   6157,   6157, 
  // 384 - 391
        -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, 
  // 392 - 399
        -12275, -12275, -12275, -12275, -12275, -12275, -12275, -12275, 
  // 400 - 407
  14353,  14353,  14353,  14353,  16401,  16401,  16401,  16401, 
  // 408 - 415
  22547,  22547,  24595,  24595,  20497,  20497,  20497,  20497, 
  // 416 - 423
  18449,  18449,  18449,  18449,  26643,  26643,  28691,  28691, 
  // 424 - 431
  30739,  30739, -32749, -32749, -30701, -30701, -28653, -28653, 
  // 432 - 439
        -26605, -26605, -24557, -24557, -22509, -22509, -20461, -20461, 
  // 440 - 447
  8207,   8207,   8207,   8207,   8207,   8207,   8207,   8207, 
  // 448 - 455
  72,     72,     72,     72,     72,     72,     72,     72, 
  // 456 - 463
  72,     72,     72,     72,     72,     72,     72,     72, 
  // 464 - 471
  72,     72,     72,     72,     72,     72,     72,     72, 
  // 472 - 479
  72,     72,     72,     72,     72,     72,     72,     72, 
  // 480 - 487
  72,     72,     72,     72,     72,     72,     72,     72, 
  // 488 - 495
  72,     72,     72,     72,     72,     72,     72,     72, 
  // 496 - 503
  72,     72,     72,     72,     72,     72,     72,     72, 
  // 504 - 511
  72,     72,     72,     72,     72,     72,     72,     72, 
  // 512 - 519
  104,    104,    104,    104,    104,    104,    104,    104, 
  // 520 - 527
  104,    104,    104,    104,    104,    104,    104,    104, 
  // 528 - 535
  104,    104,    104,    104,    104,    104,    104,    104, 
  // 536 - 543
  104,    104,    104,    104,    104,    104,    104,    104, 
  // 544 - 551
  104,    104,    104,    104,    104,    104,    104,    104, 
  // 552 - 559
  104,    104,    104,    104,    104,    104,    104,    104, 
  // 560 - 567
  104,    104,    104,    104,    104,    104,    104,    104, 
  // 568 - 575
  104,    104,    104,    104,    104,    104,    104,    104, 
  // 576 - 583
  4107,   4107,   4107,   4107,   4107,   4107,   4107,   4107, 
  // 584 - 591
  4107,   4107,   4107,   4107,   4107,   4107,   4107,   4107, 
  // 592 - 599
  4107,   4107,   4107,   4107,   4107,   4107,   4107,   4107, 
  // 600 - 607
  4107,   4107,   4107,   4107,   4107,   4107,   4107,   4107, 
  // 608 - 615
  266,    266,    266,    266,    266,    266,    266,    266, 
  // 616 - 623
  266,    266,    266,    266,    266,    266,    266,    266, 
  // 624 - 631
  266,    266,    266,    266,    266,    266,    266,    266, 
  // 632 - 639
  266,    266,    266,    266,    266,    266,    266,    266, 
  // 640 - 647
  298,    298,    298,    298,    298,    298,    298,    298, 
  // 648 - 655
  298,    298,    298,    298,    298,    298,    298,    298, 
  // 656 - 663
  298,    298,    298,    298,    298,    298,    298,    298, 
  // 664 - 671
  298,    298,    298,    298,    298,    298,    298,    298, 
  // 672 - 679
  524,    524,    524,    524,    524,    524,    524,    524, 
  // 680 - 687
  524,    524,    524,    524,    524,    524,    524,    524, 
  // 688 - 695
  556,    556,    556,    556,    556,    556,    556,    556, 
  // 696 - 703
  556,    556,    556,    556,    556,    556,    556,    556, 
  // 704 - 711
  136,    136,    136,    136,    136,    136,    136,    136, 
  // 712 - 719
  136,    136,    136,    136,    136,    136,    136,    136, 
  // 720 - 727
  136,    136,    136,    136,    136,    136,    136,    136, 
  // 728 - 735
  136,    136,    136,    136,    136,    136,    136,    136, 
  // 736 - 743
  136,    136,    136,    136,    136,    136,    136,    136, 
  // 744 - 751
  136,    136,    136,    136,    136,    136,    136,    136, 
  // 752 - 759
  136,    136,    136,    136,    136,    136,    136,    136, 
  // 760 - 767
  136,    136,    136,    136,    136,    136,    136,    136, 
  // 768 - 775
  168,    168,    168,    168,    168,    168,    168,    168, 
  // 776 - 783
  168,    168,    168,    168,    168,    168,    168,    168, 
  // 784 - 791
  168,    168,    168,    168,    168,    168,    168,    168, 
  // 792 - 799
  168,    168,    168,    168,    168,    168,    168,    168, 
  // 800 - 807
  168,    168,    168,    168,    168,    168,    168,    168, 
  // 808 - 815
  168,    168,    168,    168,    168,    168,    168,    168, 
  // 816 - 823
  168,    168,    168,    168,    168,    168,    168,    168, 
  // 824 - 831
  168,    168,    168,    168,    168,    168,    168,    168, 
  // 832 - 839
  460,    460,    460,    460,    460,    460,    460,    460, 
  // 840 - 847
  460,    460,    460,    460,    460,    460,    460,    460, 
  // 848 - 855
  492,    492,    492,    492,    492,    492,    492,    492, 
  // 856 - 863
  492,    492,    492,    492,    492,    492,    492,    492, 
  // 864 - 871
  2059,   2059,   2059,   2059,   2059,   2059,   2059,   2059, 
  // 872 - 879
  2059,   2059,   2059,   2059,   2059,   2059,   2059,   2059, 
  // 880 - 887
  2059,   2059,   2059,   2059,   2059,   2059,   2059,   2059, 
  // 888 - 895
  2059,   2059,   2059,   2059,   2059,   2059,   2059,   2059, 
  // 896 - 903
  200,    200,    200,    200,    200,    200,    200,    200, 
  // 904 - 911
  200,    200,    200,    200,    200,    200,    200,    200, 
  // 912 - 919
  200,    200,    200,    200,    200,    200,    200,    200, 
  // 920 - 927
  200,    200,    200,    200,    200,    200,    200,    200, 
  // 928 - 935
  200,    200,    200,    200,    200,    200,    200,    200, 
  // 936 - 943
  200,    200,    200,    200,    200,    200,    200,    200, 
  // 944 - 951
  200,    200,    200,    200,    200,    200,    200,    200, 
  // 952 - 959
  200,    200,    200,    200,    200,    200,    200,    200, 
  // 960 - 967
  232,    232,    232,    232,    232,    232,    232,    232, 
  // 968 - 975
  232,    232,    232,    232,    232,    232,    232,    232, 
  // 976 - 983
  232,    232,    232,    232,    232,    232,    232,    232, 
  // 984 - 991
  232,    232,    232,    232,    232,    232,    232,    232, 
  // 992 - 999
  232,    232,    232,    232,    232,    232,    232,    232, 
  // 1000 - 1007
  232,    232,    232,    232,    232,    232,    232,    232, 
  // 1008 - 1015
  232,    232,    232,    232,    232,    232,    232,    232, 
  // 1016 - 1023
  232,    232,    232,    232,    232,    232,    232,    232, 
    };

    // Additional make up codes for both White and Black runs
    static ushort[] additionalMakeup = 
    {
      28679,  28679,  31752,  32777,  
      33801,  34825,  35849,  36873,
      29703,  29703,  30727,  30727, 
      37897,  38921,  39945,  40969
    };

    // Initial black run look up table, uses the first 4 bits of a code
    static short[] initBlack = {
  // 0 - 7
  3226,  6412,    200,    168,    38,     38,    134,    134,
  // 8 - 15
  100,    100,    100,    100,    68,     68,     68,     68
    };

    // 
    static short[] twoBitBlack = { 292, 260, 226, 226 };   // 0 - 3

    // Main black run table, using the last 9 bits of possible 13 bit code
    static short[] black = {
  // 0 - 7
  62,     62,     30,     30,     0,      0,      0,      0, 
  // 8 - 15
  0,      0,      0,      0,      0,      0,      0,      0, 
  // 16 - 23
  0,      0,      0,      0,      0,      0,      0,      0, 
  // 24 - 31
  0,      0,      0,      0,      0,      0,      0,      0, 
  // 32 - 39
  3225,   3225,   3225,   3225,   3225,   3225,   3225,   3225, 
  // 40 - 47
  3225,   3225,   3225,   3225,   3225,   3225,   3225,   3225, 
  // 48 - 55
  3225,   3225,   3225,   3225,   3225,   3225,   3225,   3225, 
  // 56 - 63
  3225,   3225,   3225,   3225,   3225,   3225,   3225,   3225, 
  // 64 - 71
  588,    588,    588,    588,    588,    588,    588,    588, 
  // 72 - 79
  1680,   1680,  20499,  22547,  24595,  26643,   1776,   1776, 
  // 80 - 87
  1808,   1808, -24557, -22509, -20461, -18413,   1904,   1904, 
  // 88 - 95
  1936,   1936, -16365, -14317,    782,    782,    782,    782, 
  // 96 - 103
  814,    814,    814,    814, -12269, -10221,  10257,  10257, 
  // 104 - 111
  12305,  12305,  14353,  14353,  16403,  18451,   1712,   1712, 
  // 112 - 119
  1744,   1744,  28691,  30739, -32749, -30701, -28653, -26605, 
  // 120 - 127
  2061,   2061,   2061,   2061,   2061,   2061,   2061,   2061, 
  // 128 - 135
  424,    424,    424,    424,    424,    424,    424,    424, 
  // 136 - 143
  424,    424,    424,    424,    424,    424,    424,    424, 
  // 144 - 151
  424,    424,    424,    424,    424,    424,    424,    424, 
  // 152 - 159
  424,    424,    424,    424,    424,    424,    424,    424, 
  // 160 - 167
  750,    750,    750,    750,   1616,   1616,   1648,   1648, 
  // 168 - 175
  1424,   1424,   1456,   1456,   1488,   1488,   1520,   1520, 
  // 176 - 183
  1840,   1840,   1872,   1872,   1968,   1968,   8209,   8209, 
  // 184 - 191
  524,    524,    524,    524,    524,    524,    524,    524, 
  // 192 - 199
  556,    556,    556,    556,    556,    556,    556,    556, 
  // 200 - 207
  1552,   1552,   1584,   1584,   2000,   2000,   2032,   2032, 
  // 208 - 215
  976,    976,   1008,   1008,   1040,   1040,   1072,   1072, 
  // 216 - 223
  1296,   1296,   1328,   1328,    718,    718,    718,    718, 
  // 224 - 231
  456,    456,    456,    456,    456,    456,    456,    456, 
  // 232 - 239
  456,    456,    456,    456,    456,    456,    456,    456, 
  // 240 - 247
  456,    456,    456,    456,    456,    456,    456,    456, 
  // 248 - 255
  456,    456,    456,    456,    456,    456,    456,    456, 
  // 256 - 263
  326,    326,    326,    326,    326,    326,    326,    326, 
  // 264 - 271
  326,    326,    326,    326,    326,    326,    326,    326, 
  // 272 - 279
  326,    326,    326,    326,    326,    326,    326,    326, 
  // 280 - 287
  326,    326,    326,    326,    326,    326,    326,    326, 
  // 288 - 295
  326,    326,    326,    326,    326,    326,    326,    326, 
  // 296 - 303
  326,    326,    326,    326,    326,    326,    326,    326, 
  // 304 - 311
  326,    326,    326,    326,    326,    326,    326,    326, 
  // 312 - 319
  326,    326,    326,    326,    326,    326,    326,    326, 
  // 320 - 327
  358,    358,    358,    358,    358,    358,    358,    358, 
  // 328 - 335
  358,    358,    358,    358,    358,    358,    358,    358, 
  // 336 - 343
  358,    358,    358,    358,    358,    358,    358,    358, 
  // 344 - 351
  358,    358,    358,    358,    358,    358,    358,    358, 
  // 352 - 359
  358,    358,    358,    358,    358,    358,    358,    358, 
  // 360 - 367
  358,    358,    358,    358,    358,    358,    358,    358, 
  // 368 - 375
  358,    358,    358,    358,    358,    358,    358,    358, 
  // 376 - 383
  358,    358,    358,    358,    358,    358,    358,    358, 
  // 384 - 391
  490,    490,    490,    490,    490,    490,    490,    490, 
  // 392 - 399
  490,    490,    490,    490,    490,    490,    490,    490, 
  // 400 - 407
  4113,   4113,   6161,   6161,    848,    848,    880,    880, 
  // 408 - 415
  912,    912,    944,    944,    622,    622,    622,    622, 
  // 416 - 423
  654,    654,    654,    654,   1104,   1104,   1136,   1136, 
  // 424 - 431
  1168,   1168,   1200,   1200,   1232,   1232,   1264,   1264, 
  // 432 - 439
  686,    686,    686,    686,   1360,   1360,   1392,   1392, 
  // 440 - 447
  12,     12,     12,     12,     12,     12,     12,     12, 
  // 448 - 455
  390,    390,    390,    390,    390,    390,    390,    390, 
  // 456 - 463
  390,    390,    390,    390,    390,    390,    390,    390, 
  // 464 - 471
  390,    390,    390,    390,    390,    390,    390,    390, 
  // 472 - 479
  390,    390,    390,    390,    390,    390,    390,    390, 
  // 480 - 487
  390,    390,    390,    390,    390,    390,    390,    390, 
  // 488 - 495
  390,    390,    390,    390,    390,    390,    390,    390, 
  // 496 - 503
  390,    390,    390,    390,    390,    390,    390,    390, 
  // 504 - 511
  390,    390,    390,    390,    390,    390,    390,    390, 
    };

    static byte[] twoDCodes = {
  // 0 - 7
  80,     88,     23,     71,     30,     30,     62,     62, 
  // 8 - 15
  4,      4,      4,      4,      4,      4,      4,      4, 
  // 16 - 23
  11,     11,     11,     11,     11,     11,     11,     11, 
  // 24 - 31
  11,     11,     11,     11,     11,     11,     11,     11, 
  // 32 - 39
  35,     35,     35,     35,     35,     35,     35,     35, 
  // 40 - 47
  35,     35,     35,     35,     35,     35,     35,     35, 
  // 48 - 55
  51,     51,     51,     51,     51,     51,     51,     51, 
  // 56 - 63
  51,     51,     51,     51,     51,     51,     51,     51, 
  // 64 - 71
  41,     41,     41,     41,     41,     41,     41,     41, 
  // 72 - 79
  41,     41,     41,     41,     41,     41,     41,     41, 
  // 80 - 87
  41,     41,     41,     41,     41,     41,     41,     41, 
  // 88 - 95
  41,     41,     41,     41,     41,     41,     41,     41, 
  // 96 - 103
  41,     41,     41,     41,     41,     41,     41,     41, 
  // 104 - 111
  41,     41,     41,     41,     41,     41,     41,     41, 
  // 112 - 119
  41,     41,     41,     41,     41,     41,     41,     41, 
  // 120 - 127
  41,     41,     41,     41,     41,     41,     41,     41, 
    };



#endregion static tables


    #region constructors


    public CompressionCCITT()
      : base() { }




    //public CompressionCCITT(BlockBitmapSource currImage)
    //  : base()
    //{

    //  if (currImage.TiffMetadata.PixelFormat.BitsPerPixel != 1)
    //    throw new ArgumentException("sorry unsupported pixel depth for fax compression");

    //  _decompressAs8bpp = currImage.DecodeBilevelAs8bpp;

    //  //if (currImage.TiffMetadata.IsTiled)
    //  //  if (currImage.TiffMetadata.NumOfHorizontalBlocks > 1)
    //  //    throw new ArgumentException("tiled image with ccitt compression is unsupported now");

    //  _fillOrder = currImage.TiffMetadata.FillOrder;
    //  _tiffT6Options = currImage.TiffMetadata.T6Options;
    //  //_tiffT4Options = ((BilevelBand)currImage.Bands[BandType.Bilevel]).T4Options;

    //  this.bitPointer = 0;
    //  this.bytePointer = 0;
    //  //
    //  //this.prevChangingElems = new int[w];
    //  //this.currChangingElems = new int[w];
    //}


    #endregion constructors


    #region public members



    public override CompressionType[] CompressionTypes
    {
      get { return new CompressionType[] { CompressionType.CCITT_T4, CompressionType.CCITT_T6 }; }
    }




    //public bool DecompressAs8bpp
    //{
    //  get { return _decompressAs8bpp; }
    //  set { _decompressAs8bpp = value; }
    //}

    //public override Compression CreateCompression(TiffBitmapPage currImage)
    //{
    //  return new CompressionCCITT(currImage);

    //}



    public override byte[] DecompressBlock(BitmapBlock comprBlock, byte[] comprData, int srcBitsPerSample) //decode whole image block
    {

      //if (comprBlock.Parent.TiffMetadata.PixelFormat.BitsPerPixel != 1)
      //  throw new ArgumentException("sorry unsupported pixel depth for fax compression");

      _decompressAs8bpp = comprBlock.Parent.DecodeBilevelAs8bpp;

      _tiffT6Options = comprBlock.Parent.TiffMetadata.T6Options;
      _fillOrder = comprBlock.Parent.TiffMetadata.FillOrder;
      //_tiffT4Options = ((BilevelBand)currImage.Bands[BandType.Bilevel]).T4Options;

      //this.w = comprBlock.Bounds.Width; //stripped image
      //this.h = comprBlock.Bounds.Height;
      this.w = comprBlock.PaddingWidth; //stripped image
      this.h = comprBlock.PaddingHeight;

      //if (_image == null)
      //  throw new InvalidOperationException("no image presents to decompress");

      if (prevChangingElems == null)
      {
        prevChangingElems = new int[w];
        currChangingElems = new int[w];
      }

      if (prevChangingElems.Length != this.w)
      {
        Array.Resize<int>(ref prevChangingElems, w);
        Array.Resize<int>(ref currChangingElems, w);
      }

      int startColumn = 0;
      int scanlineStride;

      if (!_decompressAs8bpp && srcBitsPerSample == 1)
        //scanlineStride = BitmapBlock.GetStrideLenght(_image.PixelWidth, _image.TiffMetadata.PixelFormat.BitsPerPixel);
        scanlineStride = BitmapBlock.GetStrideLenght(comprBlock.PaddingWidth, 1);
      else
        scanlineStride = BitmapBlock.GetStrideLenght(comprBlock.PaddingWidth, 8);

      //int outDataLen = scanlineStride * comprBlock.Bounds.Height;
      int outDataLen = scanlineStride * comprBlock.PaddingHeight;

      if (_uncompressedDataBuff == null)
        _uncompressedDataBuff = new byte[outDataLen];
      else
      {
        if (_uncompressedDataBuff.Length != outDataLen)
          Array.Resize<byte>(ref _uncompressedDataBuff, outDataLen);

        Array.Clear(_uncompressedDataBuff, 0, _uncompressedDataBuff.Length);
      }
        
      decodeT6(_uncompressedDataBuff, comprData, scanlineStride, startColumn, comprBlock.PaddingHeight, _tiffT6Options);

      return _uncompressedDataBuff;

    }




    ///// <summary>
    ///// decodes image into new bitmap created by this function
    ///// </summary>
    //public override void Decompress()
    //{

    //  byte[] inputData;  //disk data buffer

    //  //create new byte Array to decompress into
    //  Bitmap bmp = new Bitmap(_image.Width, _image.Height, PixelFormat.Format1bppIndexed);
    //  Rectangle rct = new Rectangle(0, 0, _image.Width, _image.Height);
    //  BitmapData bd = bmp.LockBits(new Rectangle(0, 0, _image.Width, _image.Height), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);

    //  //get bitmap start pointer
    //  byte* browPtr = (byte*)bd.Scan0;

    //  int startColumn = 0; //todo: chenge to decompress only part of image...

    //  foreach (Block b in ((BilevelBand)_image.Bands[BandType.Bilevel]).Blocks)
    //  {

    //    this.w = b.Width; //stripped image
    //    this.h = b.Height;

    //    //might be not necessary... it is initialized in constructor
    //    // to largest possible value
    //    if (prevChangingElems.Length != w)
    //    {
    //      Array.Resize<int>(ref prevChangingElems, w);
    //      Array.Resize<int>(ref currChangingElems, w);
    //      //this.prevChangingElems = new int[w];
    //      //this.currChangingElems = new int[w];
    //    }

    //    //read compressed data from tiff file
    //    _tiffReader.BaseStream.Seek(b.Offset, System.IO.SeekOrigin.Begin);
    //    inputData = _tiffReader.ReadBytes(b.CompressedSize);

    //    //select compression submethod
    //    switch (_image.Metadata.Compression)
    //    {
    //      case CompressionType.CCITT_T6:
    //        decodeT6(browPtr, inputData, bd.Stride, startColumn, b.Height, _tiffT6Options);
    //        break;
    //    }
    //    browPtr += (bd.Stride * b.Height); //strange stride size in .NET !!!
    //  }
    //  bmp.UnlockBits(bd);
    //  bmp.Save("e:\\rastry\\test.bmp", ImageFormat.Bmp);
    //}


    #endregion public members


    #region private members


    // One-dimensional decoding methods
    private void decode1D(byte[] decompressedData, byte[] compData,
                         int startX, int height)
    {
      this.data = compData;

      int lineOffset = 0;
      int scanlineStride = (w + 7) / 8;

      bitPointer = 0;
      bytePointer = 0;

      for (int i = 0; i < height; i++)
      {
        decodeNextScanline(decompressedData, lineOffset, startX);
        lineOffset += scanlineStride;
      }
    }




    /// <summary>
    /// Two-dimensional decoding methods
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="compData"></param>
    /// <param name="startX"></param>
    /// <param name="height"></param>
    /// <param name="tiffT4Options"></param>
    private void decode2D(byte[] decompressedDataBuff,
                         byte[] compData,
                         int startX,
                         int height,
                         long tiffT4Options)
    {
      this.data = compData;
      compression = 3;

      bitPointer = 0;
      bytePointer = 0;

      int scanlineStride = (w + 7) / 8;

      int a0, a1, b1, b2;
      int[] b = new int[2];
      int entry, code, bits;
      bool isWhite;
      int currIndex = 0;
      int[] temp;

      // fillBits - dealt with this in readEOL
      // 1D/2D encoding - dealt with this in readEOL

      // uncompressedMode - haven't dealt with this yet.


      oneD = (int)(tiffT4Options & 0x01);

      //uncompressedMode = (int)((tiffT4Options & 0x02) >> 1);
      if (_tiffT6Options == TiffFaxT6Option.Uncompressed)
        throw new NotImplementedException("uncompressed ccitt unsupported");

      fillBits = (int)((tiffT4Options & 0x04) >> 2);

      // The data must start with an EOL code
      if (readEOL() != 1)
      {
        throw new InvalidOperationException("TIFFFaxDecoder3");
      }

      int lineOffset = 0;
      int bitOffset;

      // Then the 1D encoded scanline data will occur, changing elements
      // array gets set.
      decodeNextScanline(decompressedDataBuff, lineOffset, startX);
      lineOffset += scanlineStride;

      for (int lines = 1; lines < height; lines++)
      {

        // Every line must begin with an EOL followed by a bit which
        // indicates whether the following scanline is 1D or 2D encoded.
        if (readEOL() == 0)
        {
          // 2D encoded scanline follows    

          // Initialize previous scanlines changing elements, and 
          // initialize current scanline's changing elements array
          temp = prevChangingElems;
          prevChangingElems = currChangingElems;
          currChangingElems = temp;
          currIndex = 0;

          // a0 has to be set just before the start of this scanline.
          a0 = -1;
          isWhite = true;
          bitOffset = startX;

          lastChangingElement = 0;

          while (bitOffset < w)
          {
            // Get the next changing element
            getNextChangingElement(a0, isWhite, b);

            b1 = b[0];
            b2 = b[1];

            // Get the next seven bits
            entry = nextLesserThan8Bits(7);

            // Run these through the 2DCodes table
            entry = (int)(twoDCodes[entry] & 0xff);

            // Get the code and the number of bits used up
            code = (entry & 0x78) >> 3;
            bits = entry & 0x07;

            if (code == 0)
            {
              if (!isWhite)
              {
                setToBlack(decompressedDataBuff, lineOffset, bitOffset,
                           b2 - bitOffset);
              }
              bitOffset = a0 = b2;

              // Set pointer to consume the correct number of bits.
              updatePointer(7 - bits);
            }
            else if (code == 1)
            {
              // Horizontal
              updatePointer(7 - bits);

              // identify the next 2 codes.
              int number;
              if (isWhite)
              {
                number = decodeWhiteCodeWord();
                bitOffset += number;
                currChangingElems[currIndex++] = bitOffset;

                number = decodeBlackCodeWord();
                setToBlack(decompressedDataBuff, lineOffset, bitOffset, number);
                bitOffset += number;
                currChangingElems[currIndex++] = bitOffset;
              }
              else
              {
                number = decodeBlackCodeWord();
                setToBlack(decompressedDataBuff, lineOffset, bitOffset, number);
                bitOffset += number;
                currChangingElems[currIndex++] = bitOffset;

                number = decodeWhiteCodeWord();
                bitOffset += number;
                currChangingElems[currIndex++] = bitOffset;
              }

              a0 = bitOffset;
            }
            else if (code <= 8)
            {
              // Vertical
              a1 = b1 + (code - 5);

              currChangingElems[currIndex++] = a1;

              // We write the current color till a1 - 1 pos,
              // since a1 is where the next color starts
              if (!isWhite)
              {
                setToBlack(decompressedDataBuff, lineOffset, bitOffset,
                           a1 - bitOffset);
              }
              bitOffset = a0 = a1;
              isWhite = !isWhite;

              updatePointer(7 - bits);
            }
            else
            {
              throw new InvalidOperationException("TIFFFaxDecoder4");
            }
          }

          // Add the changing element beyond the current scanline for the
          // other color too
          currChangingElems[currIndex++] = bitOffset;
          changingElemSize = currIndex;
        }
        else
        {
          // 1D encoded scanline follows
          decodeNextScanline(decompressedDataBuff, lineOffset, startX);
        }

        lineOffset += scanlineStride;
      }
    }





    /// <summary>
    /// tiff fax CCITT T6 decoder
    /// </summary>
    /// <param name="bmpPtr">pointer to bitonal bitmap</param>
    /// <param name="compData">compressed data byte array</param>
    /// <param name="scanlineStride">size of bitmap stride in bytes</param>
    /// <param name="startX">decoder start row position, must correspond to bmpPtr position</param>
    /// <param name="height">height of current block in pixels</param>
    /// <param name="tiffT6Options"></param>
    public void decodeT6( byte[] decompressedDataBuff, byte[] compData,
                          int scanlineStride,
                          int startX,
                          int height,
                          TiffFaxT6Option tiffT6Options)
    {

      this.data = compData;
      compression = 4;

      bitPointer = 0;
      bytePointer = 0;

      //int scanlineStride = (w + 7) / 8;

      int a0, a1, b1, b2;
      int entry, code, bits;
      bool isWhite;
      int currIndex;
      int[] temp;

      // Return values from getNextChangingElement
      int[] b = new int[2];

      // uncompressedMode - have written some code for this, but this 
      // has not been tested due to lack of test images using this optional

      //uncompressedMode = (int)((tiffT6Options & 0x02) >> 1);
      if (_tiffT6Options == TiffFaxT6Option.Uncompressed)
        throw new NotImplementedException("uncompressed ccitt unsupported");

      // Local cached reference
      int[] cce = currChangingElems;

      // Assume invisible preceding row of all white pixels and insert
      // both black and white changing elements beyond the end of this
      // imaginary scanline.
      changingElemSize = 0;
      cce[changingElemSize++] = w;
      cce[changingElemSize++] = w;

      int lineOffset = 0;
      int bitOffset;

      for (int lines = 0; lines < height; lines++)
      {
        // a0 has to be set just before the start of the scanline.
        a0 = -1;
        isWhite = true;

        // Assign the changing elements of the previous scanline to 
        // prevChangingElems and start putting this new scanline's
        // changing elements into the currChangingElems.
        temp = prevChangingElems;
        prevChangingElems = currChangingElems;
        cce = currChangingElems = temp;
        currIndex = 0;

        // Start decoding the scanline at startX in the raster
        bitOffset = startX;

        // Reset search start position for getNextChangingElement
        lastChangingElement = 0;

        // Till one whole scanline is decoded
        while (bitOffset < w)
        {
          // Get the next changing element 
          getNextChangingElement(a0, isWhite, b);
          b1 = b[0];
          b2 = b[1];

          // Get the next seven bits
          entry = nextLesserThan8Bits(7);
          // Run these through the 2DCodes table
          entry = (int)(twoDCodes[entry] & 0xff);

          // Get the code and the number of bits used up
          code = (entry & 0x78) >> 3;
          bits = entry & 0x07;

          if (code == 0)
          { // Pass
            // We always assume WhiteIsZero format for fax.
            if (!isWhite)
            {
              if(_decompressAs8bpp)
                setToBlack8bpp(decompressedDataBuff, lineOffset, bitOffset, b2 - bitOffset);
              else
                setToBlack(decompressedDataBuff, lineOffset, bitOffset, b2 - bitOffset);
            }
            bitOffset = a0 = b2;

            // Set pointer to only consume the correct number of bits.
            updatePointer(7 - bits);
          }
          else if (code == 1)
          { // Horizontal
            // Set pointer to only consume the correct number of bits.
            updatePointer(7 - bits);

            // identify the next 2 alternating color codes.
            int number;
            if (isWhite)
            {
              // Following are white and black runs
              number = decodeWhiteCodeWord();
              bitOffset += number;
              cce[currIndex++] = bitOffset;

              number = decodeBlackCodeWord();

              if(_decompressAs8bpp)
                setToBlack8bpp(decompressedDataBuff, lineOffset, bitOffset, number);
              else
                setToBlack(decompressedDataBuff, lineOffset, bitOffset, number);

              bitOffset += number;
              cce[currIndex++] = bitOffset;
            }
            else
            {
              // First a black run and then a white run follows
              number = decodeBlackCodeWord();

              if (_decompressAs8bpp)
                setToBlack8bpp(decompressedDataBuff, lineOffset, bitOffset, number);
              else
                setToBlack(decompressedDataBuff, lineOffset, bitOffset, number);

              bitOffset += number;
              cce[currIndex++] = bitOffset;

              number = decodeWhiteCodeWord();
              bitOffset += number;
              cce[currIndex++] = bitOffset;
            }

            a0 = bitOffset;
          }
          else if (code <= 8)
          { // Vertical
            a1 = b1 + (code - 5);
            cce[currIndex++] = a1;

            // We write the current color till a1 - 1 pos,
            // since a1 is where the next color starts
            if (!isWhite)
            {
              if(_decompressAs8bpp)
                setToBlack8bpp(decompressedDataBuff, lineOffset, bitOffset, a1 - bitOffset);
              else
                setToBlack(decompressedDataBuff, lineOffset, bitOffset, a1 - bitOffset);
            }
            bitOffset = a0 = a1;
            isWhite = !isWhite;

            updatePointer(7 - bits);
          }
          else if (code == 11)
          {
            if (nextLesserThan8Bits(3) != 7)
            {
              throw new InvalidOperationException("TIFFFaxDecoder5");
            }

            int zeros = 0;
            bool exit = false;

            while (!exit)
            {
              while (nextLesserThan8Bits(1) != 1)
              {
                zeros++;
              }

              if (zeros > 5)
              {
                // Exit code

                // Zeros before exit code
                zeros = zeros - 6;

                if (!isWhite && (zeros > 0))
                {
                  cce[currIndex++] = bitOffset;
                }

                // Zeros before the exit code
                bitOffset += zeros;
                if (zeros > 0)
                {
                  // Some zeros have been written
                  isWhite = true;
                }

                // Read in the bit which specifies the color of
                // the following run
                if (nextLesserThan8Bits(1) == 0)
                {
                  if (!isWhite)
                  {
                    cce[currIndex++] = bitOffset;
                  }
                  isWhite = true;
                }
                else
                {
                  if (isWhite)
                  {
                    cce[currIndex++] = bitOffset;
                  }
                  isWhite = false;
                }

                exit = true;
              }

              if (zeros == 5)
              {
                if (!isWhite)
                {
                  cce[currIndex++] = bitOffset;
                }
                bitOffset += zeros;

                // Last thing written was white
                isWhite = true;
              }
              else
              {
                bitOffset += zeros;

                cce[currIndex++] = bitOffset;

                if(_decompressAs8bpp)
                  setToBlack8bpp(decompressedDataBuff, lineOffset, bitOffset, 1);
                else
                  setToBlack(decompressedDataBuff, lineOffset, bitOffset, 1);

                ++bitOffset;

                // Last thing written was black
                isWhite = false;
              }

            }
          }
          else
          {
            throw new InvalidOperationException("TIFFFaxDecoder5");
          }
        }

        // Add the changing element beyond the current scanline for the
        // other color too
        cce[currIndex++] = bitOffset;

        // Number of changing elements in this scanline.
        changingElemSize = currIndex;

        lineOffset += scanlineStride;
      }
    }



    private void decodeNextScanline(byte[] buffer,
                               int lineOffset, int bitOffset)
    {
      int bits = 0, code = 0, isT = 0;
      int current, entry, twoBits;
      bool isWhite = true;

      // Initialize starting of the changing elements array
      changingElemSize = 0;

      // While scanline not complete
      while (bitOffset < w)
      {
        while (isWhite)
        {
          // White run
          current = nextNBits(10);
          entry = white[current];

          // Get the 3 fields from the entry
          isT = entry & 0x0001;
          bits = (entry >> 1) & 0x0f;

          if (bits == 12)
          {          // Additional Make up code
            // Get the next 2 bits
            twoBits = nextLesserThan8Bits(2);
            // Consolidate the 2 new bits and last 2 bits into 4 bits
            current = ((current << 2) & 0x000c) | twoBits;
            entry = additionalMakeup[current];
            bits = (entry >> 1) & 0x07;     // 3 bits 0000 0111
            code = (entry >> 4) & 0x0fff;  // 12 bits
            bitOffset += code; // Skip white run

            updatePointer(4 - bits);
          }
          else if (bits == 0)
          {     // ERROR
            throw new InvalidOperationException("TIFFFaxDecoder0");
          }
          else if (bits == 15)
          {    // EOL
            throw new InvalidOperationException("TIFFFaxDecoder1");
          }
          else
          {
            // 11 bits - 0000 0111 1111 1111 = 0x07ff
            code = (entry >> 5) & 0x07ff;
            bitOffset += code;

            updatePointer(10 - bits);
            if (isT == 0)
            {
              isWhite = false;
              currChangingElems[changingElemSize++] = bitOffset;
            }
          }
        }

        // Check whether this run completed one width, if so 
        // advance to next byte boundary for compression = 2.
        if (bitOffset == w)
        {
          if (compression == 2)
          {
            advancePointer();
          }
          break;
        }

        while (isWhite == false)
        {
          // Black run
          current = nextLesserThan8Bits(4);
          entry = initBlack[current];

          // Get the 3 fields from the entry
          isT = entry & 0x0001;
          bits = (entry >> 1) & 0x000f;
          code = (entry >> 5) & 0x07ff;

          if (code == 100)
          {
            current = nextNBits(9);
            entry = black[current];

            // Get the 3 fields from the entry
            isT = entry & 0x0001;
            bits = (entry >> 1) & 0x000f;
            code = (entry >> 5) & 0x07ff;

            if (bits == 12)
            {
              // Additional makeup codes
              updatePointer(5);
              current = nextLesserThan8Bits(4);
              entry = additionalMakeup[current];
              bits = (entry >> 1) & 0x07;     // 3 bits 0000 0111
              code = (entry >> 4) & 0x0fff;  // 12 bits

              setToBlack(buffer, lineOffset, bitOffset, code);
              bitOffset += code;

              updatePointer(4 - bits);
            }
            else if (bits == 15)
            {
              // EOL code
              throw new InvalidOperationException("TIFFFaxDecoder2");
            }
            else
            {
              setToBlack(buffer, lineOffset, bitOffset, code);
              bitOffset += code;

              updatePointer(9 - bits);
              if (isT == 0)
              {
                isWhite = true;
                currChangingElems[changingElemSize++] = bitOffset;
              }
            }
          }
          else if (code == 200)
          {
            // Is a Terminating code
            current = nextLesserThan8Bits(2);
            entry = twoBitBlack[current];
            code = (entry >> 5) & 0x07ff;
            bits = (entry >> 1) & 0x0f;

            setToBlack(buffer, lineOffset, bitOffset, code);
            bitOffset += code;

            updatePointer(2 - bits);
            isWhite = true;
            currChangingElems[changingElemSize++] = bitOffset;
          }
          else
          {
            // Is a Terminating code
            setToBlack(buffer, lineOffset, bitOffset, code);
            bitOffset += code;

            updatePointer(4 - bits);
            isWhite = true;
            currChangingElems[changingElemSize++] = bitOffset;
          }
        }

        // Check whether this run completed one width
        if (bitOffset == w)
        {
          if (compression == 2)
          {
            advancePointer();
          }
          break;
        }
      }

      currChangingElems[changingElemSize++] = bitOffset;
    }




    private void setToBlack(byte[] buffer, /*byte[] buffer*/
                            int lineOffset, int bitOffset,
                            int numBits)
    {
      int bitNum = 8 * lineOffset + bitOffset;
      int lastBit = bitNum + numBits;
      
      int byteNum = bitNum >> 3;

      // Handle bits in first byte
      int shift = bitNum & 0x7;
      if (shift > 0)
      {
        int maskVal = 1 << (7 - shift);
        byte val = buffer[byteNum];
        //byte val = *(buffer + byteNum);
        while (maskVal > 0 && bitNum < lastBit)
        {
          val |= (byte)maskVal;
          maskVal >>= 1;
          ++bitNum;
        }
        buffer[byteNum] = val;
        //*(buffer + byteNum) = val;
      }

      // Fill in 8 bits at a time
      byteNum = bitNum >> 3;
      while (bitNum < lastBit - 7)
      {
        buffer[byteNum++] = (byte)255;
        //*(buffer + (byteNum++)) = (byte)255;
        bitNum += 8;
      }

      // Fill in remaining bits
      while (bitNum < lastBit)
      {
        byteNum = bitNum >> 3;
        buffer[byteNum] |= (byte)(1 << (7 - (bitNum & 0x7)));
        //*(buffer + byteNum) |= (byte)(1 << (7 - (bitNum & 0x7)));
        ++bitNum;
      }
    }




    private void setToBlack8bpp(byte[] buffer, /*byte[] buffer*/
                        int lineOffset, int bitOffset,
                        int numBits)
    {

      //int byteNum = bitNum >> 3;
      int byteNum = lineOffset + bitOffset;
      int lastByte = byteNum + numBits;

      while (byteNum < lastByte)
      {
        buffer[byteNum++] = (byte)255;
        //*(buffer + (byteNum++)) = (byte)255;
      }
    }




    // Returns run length
    private int decodeWhiteCodeWord()
    {
      int current, entry, bits, isT, twoBits, code = -1;
      int runLength = 0;
      bool isWhite = true;

      while (isWhite)
      {
        current = nextNBits(10);
        entry = white[current];

        // Get the 3 fields from the entry
        isT = entry & 0x0001;
        bits = (entry >> 1) & 0x0f;

        if (bits == 12)
        {           // Additional Make up code
          // Get the next 2 bits
          twoBits = nextLesserThan8Bits(2);
          // Consolidate the 2 new bits and last 2 bits into 4 bits
          current = ((current << 2) & 0x000c) | twoBits;
          entry = additionalMakeup[current];
          bits = (entry >> 1) & 0x07;     // 3 bits 0000 0111
          code = (entry >> 4) & 0x0fff;   // 12 bits
          runLength += code;
          updatePointer(4 - bits);
        }
        else if (bits == 0)
        {     // ERROR
          throw new InvalidOperationException("TIFFFaxDecoder0");
        }
        else if (bits == 15)
        {    // EOL
          throw new InvalidOperationException("TIFFFaxDecoder1");
        }
        else
        {
          // 11 bits - 0000 0111 1111 1111 = 0x07ff
          code = (entry >> 5) & 0x07ff;
          runLength += code;
          updatePointer(10 - bits);
          if (isT == 0)
          {
            isWhite = false;
          }
        }
      }

      return runLength;
    }





    // Returns run length
    private int decodeBlackCodeWord()
    {
      int current, entry, bits, isT, code = -1;
      int runLength = 0;
      bool isWhite = false;

      while (!isWhite)
      {
        current = nextLesserThan8Bits(4);
        entry = initBlack[current];

        // Get the 3 fields from the entry
        isT = entry & 0x0001;
        bits = (entry >> 1) & 0x000f;
        code = (entry >> 5) & 0x07ff;

        if (code == 100)
        {
          current = nextNBits(9);
          entry = black[current];

          // Get the 3 fields from the entry
          isT = entry & 0x0001;
          bits = (entry >> 1) & 0x000f;
          code = (entry >> 5) & 0x07ff;

          if (bits == 12)
          {
            // Additional makeup codes        
            updatePointer(5);
            current = nextLesserThan8Bits(4);
            entry = additionalMakeup[current];
            bits = (entry >> 1) & 0x07;     // 3 bits 0000 0111
            code = (entry >> 4) & 0x0fff;  // 12 bits
            runLength += code;

            updatePointer(4 - bits);
          }
          else if (bits == 15)
          {
            // EOL code
            throw new InvalidOperationException("TIFFFaxDecoder2");
          }
          else
          {
            runLength += code;
            updatePointer(9 - bits);
            if (isT == 0)
            {
              isWhite = true;
            }
          }
        }
        else if (code == 200)
        {
          // Is a Terminating code
          current = nextLesserThan8Bits(2);
          entry = twoBitBlack[current];
          code = (entry >> 5) & 0x07ff;
          runLength += code;
          bits = (entry >> 1) & 0x0f;
          updatePointer(2 - bits);
          isWhite = true;
        }
        else
        {
          // Is a Terminating code
          runLength += code;
          updatePointer(4 - bits);
          isWhite = true;
        }
      }

      return runLength;
    }




    private int readEOL()
    {
      if (fillBits == 0)
      {
        if (nextNBits(12) != 1)
        {
          throw new InvalidOperationException("TIFFFaxDecoder6");
        }
      }
      else if (fillBits == 1)
      {

        // First EOL code word xxxx 0000 0000 0001 will occur
        // As many fill bits will be present as required to make
        // the EOL code of 12 bits end on a byte boundary.

        int bitsLeft = 8 - bitPointer;

        if (nextNBits(bitsLeft) != 0)
        {
          throw new InvalidOperationException("TIFFFaxDecoder8");
        }

        // If the number of bitsLeft is less than 8, then to have a 12
        // bit EOL sequence, two more bytes are certainly going to be
        // required. The first of them has to be all zeros, so ensure 
        // that.
        if (bitsLeft < 4)
        {
          if (nextNBits(8) != 0)
          {
            throw new InvalidOperationException("TIFFFaxDecoder8");
          }
        }

        // There might be a random number of fill bytes with 0s, so 
        // loop till the EOL of 0000 0001 is found, as long as all
        // the bytes preceding it are 0's.
        int n;
        while ((n = nextNBits(8)) != 1)
        {

          // If not all zeros
          if (n != 0)
          {
            throw new InvalidOperationException("TIFFFaxDecoder8");
          }
        }
      }

      // If one dimensional encoding mode, then always return 1 
      if (oneD == 0)
      {
        return 1;
      }
      else
      {
        // Otherwise for 2D encoding mode,
        // The next one bit signifies 1D/2D encoding of next line.
        return nextLesserThan8Bits(1);
      }
    }




    private void getNextChangingElement(int a0, bool isWhite, int[] ret)
    {
      // Local copies of instance variables
      int[] pce = this.prevChangingElems;
      int ces = this.changingElemSize;

      // If the previous match was at an odd element, we still
      // have to search the preceeding element.
      // int start = lastChangingElement & ~0x1;
      int start = lastChangingElement > 0 ? lastChangingElement - 1 : 0;
      if (isWhite)
      {
        start &= ~0x1; // Search even numbered elements
      }
      else
      {
        start |= 0x1; // Search odd numbered elements
      }

      int i = start;
      for (; i < ces; i += 2)
      {
        int temp = pce[i];
        if (temp > a0)
        {
          lastChangingElement = i;
          ret[0] = temp;
          break;
        }
      }

      if (i + 1 < ces)
      {
        ret[1] = pce[i + 1];
      }
    }




    private int nextNBits(int bitsToGet)
    {
      byte b, next, next2next;
      int l = data.Length - 1;
      int bp = this.bytePointer;

      if (_fillOrder == FillOrderType.MSB2LSB)
      {
        b = data[bp];

        if (bp == l)
        {
          next = 0x00;
          next2next = 0x00;
        }
        else if ((bp + 1) == l)
        {
          next = data[bp + 1];
          next2next = 0x00;
        }
        else
        {
          next = data[bp + 1];
          next2next = data[bp + 2];
        }
      }
      else if (_fillOrder == FillOrderType.LSB2MSB)
      {
        b = (byte)flipTable[data[bp] & 0xff];

        if (bp == l)
        {
          next = 0x00;
          next2next = 0x00;
        }
        else if ((bp + 1) == l)
        {
          next = (byte)flipTable[data[bp + 1] & 0xff];
          next2next = 0x00;
        }
        else
        {
          next = (byte)flipTable[data[bp + 1] & 0xff];
          next2next = (byte)flipTable[data[bp + 2] & 0xff];
        }
      }
      else
      {
        throw new InvalidOperationException("TIFFFaxDecoder7");
      }

      int bitsLeft = 8 - bitPointer;
      int bitsFromNextByte = bitsToGet - bitsLeft;
      int bitsFromNext2NextByte = 0;
      if (bitsFromNextByte > 8)
      {
        bitsFromNext2NextByte = bitsFromNextByte - 8;
        bitsFromNextByte = 8;
      }

      bytePointer++;

      int i1 = (b & table1[bitsLeft]) << (bitsToGet - bitsLeft);
      int i2 = (next & table2[bitsFromNextByte]) >> (8 - bitsFromNextByte);

      int i3 = 0;
      if (bitsFromNext2NextByte != 0)
      {
        i2 <<= bitsFromNext2NextByte;
        i3 = (next2next & table2[bitsFromNext2NextByte]) >>
      (8 - bitsFromNext2NextByte);
        i2 |= i3;
        bytePointer++;
        bitPointer = bitsFromNext2NextByte;
      }
      else
      {
        if (bitsFromNextByte == 8)
        {
          bitPointer = 0;
          bytePointer++;
        }
        else
        {
          bitPointer = bitsFromNextByte;
        }
      }

      int i = i1 | i2;
      return i;
    }




    private int nextLesserThan8Bits(int bitsToGet)
    {
      byte b, next;
      int l = data.Length - 1;
      int bp = this.bytePointer;

      if (_fillOrder == FillOrderType.MSB2LSB)
      {
        b = data[bp];
        if (bp == l)
        {
          next = 0x00;
        }
        else
        {
          next = data[bp + 1];
        }
      }
      else if (_fillOrder == FillOrderType.LSB2MSB)
      {
        b = (byte)flipTable[data[bp] & 0xff];
        if (bp == l)
        {
          next = 0x00;
        }
        else
        {
          next = (byte)flipTable[data[bp + 1] & 0xff];
        }
      }
      else
      {
        throw new InvalidOperationException("TIFFFaxDecoder7");
      }

      int bitsLeft = 8 - bitPointer;
      int bitsFromNextByte = bitsToGet - bitsLeft;

      int shift = bitsLeft - bitsToGet;
      int i1, i2;
      if (shift >= 0)
      {
        i1 = (b & table1[bitsLeft]) >> shift;
        bitPointer += bitsToGet;
        if (bitPointer == 8)
        {
          bitPointer = 0;
          bytePointer++;
        }
      }
      else
      {
        i1 = (b & table1[bitsLeft]) << (-shift);
        i2 = (next & table2[bitsFromNextByte]) >> (8 - bitsFromNextByte);

        i1 |= i2;
        bytePointer++;
        bitPointer = bitsFromNextByte;
      }

      return i1;
    }




    // Move pointer backwards by given amount of bits
    private void updatePointer(int bitsToMoveBack)
    {
      int i = bitPointer - bitsToMoveBack;

      if (i < 0)
      {
        bytePointer--;
        bitPointer = 8 + i;
      }
      else
      {
        bitPointer = i;
      }
    }




    // Move to the next byte boundary
    private bool advancePointer()
    {
      if (bitPointer != 0)
      {
        bytePointer++;
        bitPointer = 0;
      }

      return true;
    }


    #endregion private members
  }
}
